﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TestVisioCanvas.Helpers;

using Visio = Microsoft.Office.Interop.Visio;

namespace TestVisioCanvas.Wrappers
{
    /// <summary>
    /// Class that represents a Measure managed inside the (A)ISS
    /// </summary>
    public class MeasureShape : IShape
    {
        System.Windows.Point _endpoint1, _endpoint2;
        private string _name;
        private int _measureID;
        private Visio.Shape _measure;
        private double _angle;
        private MeasureType _measureType;
        private ManagedShape ShapeAtBegin, ShapeAtEnd;
        public event ShapeTransformedEventHandler ShapeTransformed;
                
        /// <summary>
        /// Public constructor of a Managed Measure
        /// </summary>
        /// <param name="Shape">The Standard Visio measure shape</param>
        /// <param name="MeasureType">The kind of the measure. Horizontal, Vertical(fixed angle) or Aligned(with variable angle)</param>
        /// <param name="FirstEndPoint">The position of the first endpoint</param>
        /// <param name="SecondEndPoint">The position of the second endpoint</param>
        public MeasureShape(Visio.Shape Shape, MeasureType MeasureType, 
            System.Windows.Point FirstEndPoint, System.Windows.Point SecondEndPoint )
        {
            _measure = Shape;
            _measureID = Shape.ID;
            _measureType = MeasureType;
            _name = Shape.Name;

            this.Endpoint1 = FirstEndPoint;
            this.Endpoint2 = SecondEndPoint;

            // The value of the angle is determined from the type of the measure
            // For Vertical or Orizontal measures, it is fixed : 90 deg or 0 deg
            // For Aligned measures it is dependent from the position of the two endpoints
            // and it is managed inside the VisioDrawingControl engine.
            switch (MeasureType)
            {
                case MeasureType.Horizontal:
                case MeasureType.HorizontalOutside:
                    Shape.CellsU["Angle"].set_Result(Visio.VisUnitCodes.visDegrees, 0);
                    break;
                case MeasureType.VerticalOutside:
                case MeasureType.Vertical:
                    Shape.CellsU["Angle"].set_Result(Visio.VisUnitCodes.visDegrees, 90);
                    break;
                case MeasureType.Aligned:    
                case MeasureType.AlignedOutside:
                    
                default: _angle = Shape.CellsU["Angle"].get_Result(Visio.VisUnitCodes.visDegrees);
                    break;
            }
        }

        /// <summary>
        /// The First endpoint of the measure
        /// </summary>
        public System.Windows.Point Endpoint1
        {
            get { return _endpoint1; }
            set 
            { 
                _endpoint1 = value;
                UpdateProperty(MeasureProperty.BeginX, value.X);
                UpdateProperty(MeasureProperty.BeginY, value.Y);
            }
        }

        /// <summary>
        /// The second endpoint of the measure
        /// </summary>
        public System.Windows.Point Endpoint2
        {
            get { return _endpoint2; }
            set 
            { 
                _endpoint2 = value;
                UpdateProperty(MeasureProperty.EndX, value.X);
                UpdateProperty(MeasureProperty.EndY, value.Y);
            }
        }

        /// <summary>
        /// The angle of the measure, readonly
        /// </summary>
        public double Angle
        {
            get { return _angle; }            
        }

        /// <summary>
        /// The ID of the underlying Visio shape
        /// </summary>
        public int ID
        {
            get { return _measureID; }
        }

        /// <summary>
        /// The underlying Visio Shape
        /// </summary>
        public Visio.Shape VisioShape
        {
            get { return _measure; }
        }

        /// <summary>
        /// Method for properties update.
        /// </summary>
        /// <param name="PropertyName">The enumeration value that represents a single property</param>
        /// <param name="value">The new value for the property</param>
        /// <returns>True if the property was updated, false if not</returns>
        private bool UpdateProperty(MeasureProperty PropertyName, double value)
        {
            try
            {
                switch (PropertyName)
                {
                        // coordinates of the first endpoint
                    case MeasureProperty.BeginX:
                        _measure.CellsU["BeginX"].set_Result(StaticUtils.VisioCentimeters, value);
                        break;
                    case MeasureProperty.BeginY:
                        _measure.CellsU["BeginY"].set_Result(StaticUtils.VisioCentimeters, value);
                        break;
                    // coordinates of the second endpoint
                    case MeasureProperty.EndX:
                        _measure.CellsU["EndX"].set_Result(StaticUtils.VisioCentimeters, value);
                        break;
                    case MeasureProperty.EndY:
                        _measure.CellsU["EndY"].set_Result(StaticUtils.VisioCentimeters, value);
                        break;
                    // coordinates of the measure's angle 
                    case MeasureProperty.Angle:
                        _measure.CellsU["Angle"].set_Result(Visio.VisUnitCodes.visDegrees, value);
                        break;
                    default:
                        return false;
                }
                return true;
            }
            catch (System.Runtime.InteropServices.COMException c)
            {
#if DEBUG
                System.Diagnostics.Debug.WriteLine(c.Message);
#endif
                return false;
            }
        }

        /// <summary>
        /// The measure can be connected to a shape
        /// </summary>
        /// <param name="shapeAtBegin">The Managed shape to the first end of the measure</param>
        /// <param name="shapeAtEnd">The Managed shape to the second end of the measure</param>
        public void Connect(ManagedShape shapeAtBegin, ManagedShape shapeAtEnd)
        {
#warning la logica va rivista completamente
            if (shapeAtBegin == null)
                throw new ArgumentNullException("shapeAtBegin");
            if (shapeAtEnd == null)
                throw new ArgumentNullException("shapeAtEnd");

            this.ShapeAtBegin = shapeAtBegin;
            this.ShapeAtEnd = shapeAtEnd;
            this.ShapeAtBegin.ShapeTransformed += new ShapeTransformedEventHandler(ShapeAtBegin_ShapeTransformed);
            this.ShapeAtEnd.ShapeTransformed += new ShapeTransformedEventHandler(ShapeAtEnd_ShapeTransformed);
        }

#warning bisogna gestire lo spostamento delle forme.
        void ShapeAtEnd_ShapeTransformed(object sender, ShapeTransformedEventArgs args)
        {
            throw new NotImplementedException();
        }

        void ShapeAtBegin_ShapeTransformed(object sender, ShapeTransformedEventArgs args)
        {
            throw new NotImplementedException();
        }
    }
}
